package com.jaws.core.common.xxljob.annotation;

import com.google.common.collect.Maps;
import com.jaws.core.common.constant.JawsFrameworkCoreConstant;
import com.jaws.core.common.log.Log;
import com.jaws.core.common.xxljob.domain.XxlJobInfo;
import com.xxl.job.core.biz.model.ReturnT;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.MultiValueMap;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * 扫描获取jawsjob 配置
 *
 * @author liangqm
 * @date 2018-07-20 15:19:19
 * @since v1.0.3
 */
public class JawsJobHandlerRegistrar implements ImportBeanDefinitionRegistrar {

	private static final Logger logger = LoggerFactory.getLogger(JawsJobHandlerRegistrar.class);

//	/**
//	 * jaws job 注解集合
//	 */
//	static List<AnnotationMetadata> jawsJobAnnotationList = Collections.synchronizedList(Lists.newArrayList());

	/**
	 * jobHandler class - XxlJobInfo
	 */
	private static Map<String, XxlJobInfo> jawsJobInfoMap = Maps.newConcurrentMap();

	public static Map<String, XxlJobInfo> getJawsJobInfoMap() {
		return jawsJobInfoMap;
	}

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		String jobHandlerClassName = importingClassMetadata.getClassName();
		logger.info(Log.op("JawsJobHandlerRegistrar.registerBeanDefinitions").kv("jobHandlerClassName", jobHandlerClassName).toString());

		MultiValueMap<String, Object> objectMultiValueMap = importingClassMetadata.getAllAnnotationAttributes(JawsJobHandler.class.getName());
		assert objectMultiValueMap != null;

		// xxlJob表单信息
		XxlJobInfo xxlJobInfo = new XxlJobInfo();

		//
		try {
			// 类加载器
			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			xxlJobInfo.setJobHandlerClass(ClassUtils.forName(jobHandlerClassName, classLoader));
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		}

		// 1. 处理 jobName ; 默认为所在class的全名，可以自定义， 长度超度255 报错提示
		String jobName = objectMultiValueMap.get("jobName").get(0).toString();
		handleJobName(xxlJobInfo, jobHandlerClassName, jobName);

		// 2. 处理 jobMethod; 判断长度是否超过255， 验证在class中存在此方法
		String jobMethod = objectMultiValueMap.get("jobMethod").get(0).toString();
		handleJobMethod(xxlJobInfo, jobHandlerClassName, jobMethod);

		// 3. 处理 jobCron; 判断长度不超过128 并且符合cron表达式语法
		String jobCron = objectMultiValueMap.get("jobCron").get(0).toString();
		handleJobCron(xxlJobInfo, jobHandlerClassName, jobCron);

		// 4. 处理任务介绍; 长度不能超过255
		String jobDesc = objectMultiValueMap.get("jobDesc").get(0).toString();
		handleJobDesc(xxlJobInfo, jobHandlerClassName, jobDesc);

		// 5. 处理下拉选项
		xxlJobInfo.setExecutorRouteStrategy(objectMultiValueMap.get("routeStrategy").get(0).toString());
		xxlJobInfo.setExecutorBlockStrategy(objectMultiValueMap.get("blockStrategy").get(0).toString());
		xxlJobInfo.setExecutorFailStrategy(objectMultiValueMap.get("failStrategy").get(0).toString());

		if (jawsJobInfoMap.get(xxlJobInfo.getExecutorHandler()) == null) {
			jawsJobInfoMap.put(xxlJobInfo.getExecutorHandler(), xxlJobInfo);
		} else {
			throw new RuntimeException(String.format("%s jobName[%s] 已经在[%s]中存在", jobHandlerClassName, jobName, jawsJobInfoMap.get(jobName).getExecutorHandler()));
		}

	}

	/**
	 * 处理任务介绍; 长度不能超过255
	 *
	 * @param xxlJobInfo          xxl job 表单信息
	 * @param jobHandlerClassName 任务处理class
	 * @param jobDesc             任务描述
	 * @author liangqm
	 * @date 2018-07-24 11:26:18
	 * @since v1.0.3
	 */
	private void handleJobDesc(XxlJobInfo xxlJobInfo, String jobHandlerClassName, String jobDesc) {
		if (jobDesc.length() > JawsFrameworkCoreConstant.JAWS_JOB_DESC_MAX_SIZE) {
			throw new RuntimeException(String.format("%s jobDesc[%s] 长度 %s , 超过最大长度 %s , 请修改jobDesc", jobHandlerClassName, jobDesc, jobDesc.length(), JawsFrameworkCoreConstant.JAWS_JOB_DESC_MAX_SIZE));
		}
		xxlJobInfo.setJobDesc(jobDesc);
	}

	/**
	 * 处理 jobCron; 判断长度不超过128 并且符合cron表达式语法
	 *
	 * @param xxlJobInfo          xxl job 表单信息
	 * @param jobHandlerClassName 任务处理class
	 * @param jobCron             任务cron 表达式
	 * @author liangqm
	 * @date 2018-07-24 11:26:18
	 * @since v1.0.3
	 */
	private void handleJobCron(XxlJobInfo xxlJobInfo, String jobHandlerClassName, String jobCron) {
		if (StringUtils.isBlank(jobCron)) {
			throw new RuntimeException(String.format("%s jobCron 不能为空", jobHandlerClassName));
		}
		if (jobCron.length() > JawsFrameworkCoreConstant.JAWS_JOB_CRON_MAX_SIZE) {
			throw new RuntimeException(String.format("%s jobCron[%s] 长度%s , 超过最大长度 %s , 请修改jobCron", jobHandlerClassName, jobCron, jobCron.length(), JawsFrameworkCoreConstant.JAWS_JOB_CRON_MAX_SIZE));
		}

		// 判断 cron 合法性,使用Quartz工具类
		if (!CronExpression.isValidExpression(jobCron)) {
			throw new RuntimeException(String.format("%s jobCron[%s]  非法cron表达式 , 请修改jobCron", jobHandlerClassName, jobCron));
		}
		xxlJobInfo.setJobCron(jobCron);
	}


	/**
	 * 处理 jobMethod; 判断长度是否超过255， 验证在class中存在此方法
	 *
	 * @param xxlJobInfo          xxl job 表单信息
	 * @param jobHandlerClassName 任务处理class
	 * @param jobMethod           方法名称
	 * @author liangqm
	 * @date 2018-07-24 11:26:18
	 * @since v1.0.3
	 */
	private void handleJobMethod(XxlJobInfo xxlJobInfo, String jobHandlerClassName, String jobMethod) {
		if (jobMethod.length() > JawsFrameworkCoreConstant.JAWS_JOB_METHOD_MAX_SIZE) {
			throw new RuntimeException(String.format("%s jobMethod[%s] 长度 %s , 超过最大长度 %s , 请修改jobMethod", jobHandlerClassName, jobMethod, jobMethod.length(), JawsFrameworkCoreConstant.JAWS_JOB_METHOD_MAX_SIZE));
		}

		try {
			Method method = Class.forName(jobHandlerClassName).getDeclaredMethod(jobMethod, String.class);
			if (!method.getReturnType().equals(ReturnT.class)) {
				throw new RuntimeException(String.format("%s jobMethod[%s] 返回类型必须为 com.xxl.job.core.biz.model.ReturnT", jobHandlerClassName, jobMethod));
			}
			xxlJobInfo.setJobExecuteMethod(method);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		} catch (NoSuchMethodException e) {
			throw new RuntimeException(String.format("%s 中没有 方法名:[%s] 参数:[String.class] 的方法", jobHandlerClassName, jobMethod));
		}
		xxlJobInfo.setJobMethod(jobMethod);
	}

	/**
	 * 处理 jobName ; 默认为所在class的全名，可以自定义， 长度超度255 报错提示
	 *
	 * @param xxlJobInfo          xxl job 表单信息
	 * @param jobHandlerClassName 任务处理class
	 * @param jobHandlerClassName 任务处理class
	 * @param jobName             任务名称
	 * @author liangqm
	 * @date 2018-07-24 11:24:18
	 * @since v1.0.3
	 */
	private void handleJobName(XxlJobInfo xxlJobInfo, String jobHandlerClassName, String jobName) {
		if (StringUtils.isBlank(jobName)) {
			jobName = jobHandlerClassName;
		}
		if (jobName.length() > JawsFrameworkCoreConstant.JAWS_JOB_NAME_MAX_SIZE) {
			throw new RuntimeException(String.format("%s jobName[%s] 长度:%s , 超过最大长度 %s , 请修改jobName", jobHandlerClassName, jobName, jobName.length(), JawsFrameworkCoreConstant.JAWS_JOB_NAME_MAX_SIZE));
		}
		xxlJobInfo.setExecutorHandler(jobName);
	}
}
